/**
 * 
 */
package com.p2p.front.service.impl;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.p2p.base.bizInterface.ChangeNotify;
import com.p2p.base.model.Money;
import com.p2p.base.util.ChangeNotifyUtil;
import com.p2p.front.dal.model.LoanInfo;
import com.p2p.front.dal.model.SysConfig;
import com.p2p.front.dal.model.TenderAutoQueue;
import com.p2p.front.dal.model.TenderAutoSetting;
import com.p2p.front.facade.UserTenderFacade;
import com.p2p.front.result.UserTenderResult;
import com.p2p.front.service.SysConfigService;
import com.p2p.front.service.TenderAutoQueueService;
import com.p2p.front.service.TenderAutoService;
import com.p2p.front.service.TenderAutoSettingService;
import com.p2p.front.service.TenderService;
import com.p2p.trans.client.facade.AccountQueryFacade;
import com.p2p.trans.client.result.AccountQueryResult;

/**
 * @author ruiqi
 *
 */
@Service("tenderAutoService")
public class TenderAutoServiceImpl implements TenderAutoService,ChangeNotify {

	private final Logger logger = LoggerFactory.getLogger(TenderAutoServiceImpl.class);
	
	private int autoPercent = 70;
	
	@Resource
	AccountQueryFacade accountQueryFacade;
	
	@Resource
	TenderAutoQueueService tenderAutoQueueService;
	
	@Resource
	TenderAutoSettingService tenderAutoSettingService;
	
	@Resource
	TenderService tenderService;
	
	@Resource
	UserTenderFacade userTenderFacade;
	
	@Resource
	SysConfigService sysConfigService;

	Set<String> breakNeedResultCode = new HashSet<String>();
	
	@PostConstruct
	public void initAutoPercent(){
		String value = sysConfigService.getValueByKey(SysConfig.ConfigKeyEnum.AutoTenderPercent);
		if(StringUtils.isNumeric(value)){
			autoPercent = Integer.valueOf(value);
		}
		
		
	}
	
	/**
	 * 对于自动投标而言，某些错误码是可以继续下一个用户的自动投标的，如用某个户余额不足，不代表下一个用户也会余额不足；但是某些错误则需要中断自动投标，如已经满标，投标状态错误等，这类标本身的错误，是无需继续处理，因为下一个通常也会失败
	 */
	public void initAutoBreakNeedResultCode(){
		
		breakNeedResultCode.add(UserTenderResult.ResultCodeEnum.tender_parameters_error.name());
		breakNeedResultCode.add(UserTenderResult.ResultCodeEnum.tender_system_exception.name());
		breakNeedResultCode.add(UserTenderResult.ResultCodeEnum.tender_common_error.name());
		breakNeedResultCode.add(UserTenderResult.ResultCodeEnum.tender_status_error.name());
		breakNeedResultCode.add(UserTenderResult.ResultCodeEnum.tender_allready_full.name());
		breakNeedResultCode.add(UserTenderResult.ResultCodeEnum.tender_auto_run.name());
		
	}
	
	public void saveSetting(TenderAutoSetting tenderAutoSetting){
		
		tenderAutoSettingService.saveSetting(tenderAutoSetting);
	}
	
	public void open(String userId,int open){
		TenderAutoSetting tenderAutoSetting = this.getSetting(userId);
		if(tenderAutoSetting==null){
			return;
		}
		/*if(tenderAutoSetting.getStatus()==open){
			TenderAutoQueue tenderAutoQueue = tenderAutoQueueService.getByUserId(userId);
			if(open==1&&tenderAutoQueue!=null)
			if(null!=tenderAutoQueueService.getByUserId(userId)){
				return;
			}
			
		}*/
		tenderAutoSetting.setStatus(open);
		//saveSetting(tenderAutoSetting);
		tenderAutoSettingService.updateStatus(tenderAutoSetting);
		
		if(open==0){
			this.outAutoQueue(tenderAutoSetting.getUserId());
			return;
		}
		Money tendMoney = checkCanQueue(tenderAutoSetting);
		
		if(tendMoney!=null&&tendMoney.getCent()>0l){
			this.inAutoQueue(tenderAutoSetting.getUserId());
		}else{
			this.outAutoQueue(tenderAutoSetting.getUserId());
		}
	}
	
	public boolean checkCanLoan(TenderAutoSetting tenderAutoSetting,LoanInfo loanInfo){
		//年利率
		double apr = loanInfo.getApr();
		//期限
		int month = loanInfo.getDeadline();
		//还款方式
		String repayMethod = loanInfo.getRepayMethod();
		
		boolean aprPass = false;
		boolean deadLindPass = false;
		boolean repayMethodPass = false;
		if(((tenderAutoSetting.getMaxRate()==null)?true:apr<=tenderAutoSetting.getMaxRate())&&(tenderAutoSetting.getMinRate()==null?true:apr>=tenderAutoSetting.getMinRate())){
			aprPass= true;
		}
		
		if((tenderAutoSetting.getMaxDeadline()==null?true:month<=tenderAutoSetting.getMaxDeadline())&&(tenderAutoSetting.getMinDeadline()==null?true:month>=tenderAutoSetting.getMinDeadline())){
			deadLindPass = true;
		}
		if(StringUtils.isBlank(tenderAutoSetting.getRepayMethod())||StringUtils.equals(tenderAutoSetting.getRepayMethod(), repayMethod)){
			repayMethodPass = true;
		}
		
		if(aprPass&&deadLindPass&&repayMethodPass){
			return true;
		}
		
		return false;
	}
	
	public Money checkCanQueue(TenderAutoSetting tenderAutoSetting){
		if(tenderAutoSetting.getStatus()==1){
			AccountQueryResult accountQueryResult = accountQueryFacade.getAccountByUserId(tenderAutoSetting.getUserId());
			if(accountQueryResult.isSuccess()){
				Money canUseBalance = accountQueryResult.getAccountVO().getCanUserBalance();
				//可用余额大于0
				if(canUseBalance.getCent()>0){
					
					long canLoanMoney = canUseBalance.getCent()-tenderAutoSetting.getLimitAmount().getCent();
					long onceAmountCent = tenderAutoSetting.getOnceAmount().getCent();
					//减去预留额大于50 方可进队列
					if(canLoanMoney>5000l){
						if(onceAmountCent<0){
							return new Money(canLoanMoney);
						}else if(canLoanMoney>=onceAmountCent){
							return new Money(onceAmountCent);
						}
					}
				}
			}
		}
		return new Money(0,0);
	}
	
	
	public boolean inAutoQueue(String userId){
		return tenderAutoQueueService.inAutoQueue(userId);
	}
	
	public boolean outAutoQueue(String userId){
		return tenderAutoQueueService.outAutoQueue(userId);
	}
	
	public void refreshAutoQueueRank(){
		tenderAutoQueueService.refreshAutoQueueRank();
	}
	
	
	public void startAutoQueue(LoanInfo loanInfo){
		
		
		/*try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}*/
		
		logger.info("start do auto tender loanId= "+loanInfo.getLid());
		
		List<TenderAutoQueue> tenderAutoQueueList = tenderAutoQueueService.listAll();
		
		logger.info("auto queue size = "+tenderAutoQueueList.size());
		Money fullAmount = loanInfo.getAmount();
		//自动投标首轮额度70%；
		Money canAutoAmount = new Money(fullAmount.getCent()*this.autoPercent/100);
		Money allAutoAmount = new Money();
		int i=0;
		for(TenderAutoQueue tenderAutoQueue:tenderAutoQueueList){
			i++;
			
			/*try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}*/
			
			TenderAutoSetting tenderAutoSertting = tenderAutoSettingService.getByUserId(tenderAutoQueue.getUserId());
			
			Money tenderMoney = checkCanQueue(tenderAutoSertting);
			
			//如果金额不能投标就出队列
			if(tenderMoney==null||tenderMoney.getCent()==0){
				outAutoQueue(tenderAutoQueue.getUserId());
				continue;
			}
			
			//检查是否和当前贷款的信息匹配
			boolean canTenderLoan = checkCanLoan(tenderAutoSertting,loanInfo);
			
			if(canTenderLoan){
				UserTenderResult tenderResult = userTenderFacade.doTenderBiz(tenderAutoQueue.getUserId(), loanInfo.getLid(), tenderMoney,1,i);
				logger.info("finish one user tender user="+tenderAutoQueue.getUserId()+" result = "+tenderResult.isSuccess()+" ");
				
				
				if(!tenderResult.isSuccess()){
					if(checkResultCodeBreakNeed(tenderResult)){
						break;
					}else{
						continue;
					}
				}
				
				
				
				//累计自动投标金额
				Money succeseTenderAmount = tenderResult.getTenderAmount();
				allAutoAmount.add(succeseTenderAmount);
				
				//再次检查
				Money limitMoney = checkCanQueue(tenderAutoSertting);				
				//如果剩余金额不能投标就出队列
				if(limitMoney==null||limitMoney.getCent()==0){
					outAutoQueue(tenderAutoQueue.getUserId());
					continue;
				}
				
				//判断是否超过自动投标比例额度
				if(allAutoAmount.getCent()>=canAutoAmount.getCent()){
					logger.error("auto amount full loanId="+loanInfo.getLid()+",allAutoAmount="+allAutoAmount.toString());
					break;
				}
				if(tenderResult.isSuccess()&&tenderResult.isTenderFull()){
					break;
				}
			}
			
		}
		if(tenderAutoQueueList.size()>0){
			this.refreshAutoQueueRank();
		}
		
	}
	
	private boolean checkResultCodeBreakNeed(UserTenderResult tenderResult){
		if(!tenderResult.isSuccess()){
			logger.info("result code ="+tenderResult.getResultCode());
			String resultCode = tenderResult.getResultCode();
			if(StringUtils.isBlank(resultCode)||breakNeedResultCode.contains(resultCode)){
				return true;
			}
		}
		return false;
	}

	@Override
	public TenderAutoSetting getSetting(String userId) {
		return tenderAutoSettingService.getByUserId(userId);
	}

	@Override
	public Integer getRankrdById(String userId) {
		return tenderAutoQueueService.getRankIdByUserId(userId);
	}

	@Override
	public boolean checkInAutoQueue(String userId) {
		return tenderAutoQueueService.checkInAutoQueueByUid(userId);
	}

	@Override
	public void change() {
		logger.info("initAutoPercent");
		initAutoPercent();
	}

	@PostConstruct
	@Override
	public void addListener() {
		ChangeNotifyUtil.addListener(SysConfigService.notifySubject, this);
	}

	
	/*private void doExcuteAutoBiz(TenderAutoQueue tenderAutoQueue,LoanInfo loanInfo){
		
		TenderAutoSetting tenderAutoSertting = tenderAutoSettingService.getByUserId(tenderAutoQueue.getUserId());
		
		Money amount = checkAutoMoney(tenderAutoSertting,loanInfo);
		
		if(amount.getCent()>0){
			UserTenderResult userResult = userTenderFacade.doTenderBiz(tenderAutoQueue.getUserId(), loanInfo.getLid(), amount);
			if(userResult.isSuccess()&&userResult.isTenderFull()){
				throw new RuntimeException();
			}else if(!userResult.isSuccess()&&StringUtils.equals(userResult.getResultCode(), UserTenderResult.ResultCodeEnum.tender_status_error.name())){
				throw new RuntimeException();
			}
		}
	}*/
}